#include"stdafx.h"
#include <jni.h>
#include <irrlicht.h>
#include <vector>
#include "ICustomizableTriangleMeshNode.h"
using namespace irr;
using namespace irr::video;
using namespace irr::scene;
using namespace irr::gui;
using namespace irr::core;
using namespace irr::io;
extern "C" {

class MyShaderCallBack : public video::IShaderConstantSetCallBack
{
public:

    virtual void OnSetConstants(video::IMaterialRendererServices* services,
            s32 userData)
    {
    }
};


	typedef enum {
		SWIG_JavaOutOfMemoryError = 1, 
		SWIG_JavaIOException, 
		SWIG_JavaRuntimeException, 
		SWIG_JavaIndexOutOfBoundsException,
		SWIG_JavaArithmeticException,
		SWIG_JavaIllegalArgumentException,
		SWIG_JavaNullPointerException,
		SWIG_JavaDirectorPureVirtual,
		SWIG_JavaUnknownError
	} SWIG_JavaExceptionCodes;

	typedef struct {
		SWIG_JavaExceptionCodes code;
		const char *java_exception;
	} SWIG_JavaExceptions_t;


	static void SWIG_JavaThrowException_(JNIEnv *jenv, SWIG_JavaExceptionCodes code, const char *msg) {
		jclass excep;
		static const SWIG_JavaExceptions_t java_exceptions[] = {
			{ SWIG_JavaOutOfMemoryError, "java/lang/OutOfMemoryError" },
			{ SWIG_JavaIOException, "java/io/IOException" },
			{ SWIG_JavaRuntimeException, "java/lang/RuntimeException" },
			{ SWIG_JavaIndexOutOfBoundsException, "java/lang/IndexOutOfBoundsException" },
			{ SWIG_JavaArithmeticException, "java/lang/ArithmeticException" },
			{ SWIG_JavaIllegalArgumentException, "java/lang/IllegalArgumentException" },
			{ SWIG_JavaNullPointerException, "java/lang/NullPointerException" },
			{ SWIG_JavaDirectorPureVirtual, "java/lang/RuntimeException" },
			{ SWIG_JavaUnknownError,  "java/lang/UnknownError" },
			{ (SWIG_JavaExceptionCodes)0,  "java/lang/UnknownError" }
		};
		const SWIG_JavaExceptions_t *except_ptr = java_exceptions;

		while (except_ptr->code != code && except_ptr->code)
			except_ptr++;

		jenv->ExceptionClear();
		excep = jenv->FindClass(except_ptr->java_exception);
		if (excep)
			jenv->ThrowNew(excep, msg);
	}

	__declspec(dllexport) jlong JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1create(JNIEnv *jenv, jclass jcls, jlong sceneNodePointer, jlong sceneManagerPointer,jint id) {
		ISceneNode*sceneNode=(ISceneNode*)sceneNodePointer;
		ISceneManager*sceneManager=(ISceneManager*)sceneManagerPointer;
		ICustomizableTriangleMeshNode*node=new ICustomizableTriangleMeshNode(sceneNode, sceneManager, id);
		
		return (jlong)node;
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1setVerticies(JNIEnv *jenv, jclass jcls, jlong nodePointer, jlongArray objArray) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}
		if(objArray==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Vertices array cannot be null");
		}
		int arrayLength=jenv->GetArrayLength(objArray);
		std::vector<S3DVertex>vertices;
		jlong*vertexPointers=jenv->GetLongArrayElements(objArray,0);
		for(int i=0;i<arrayLength;i++){
			vertices.push_back(*(S3DVertex*)vertexPointers[i]);
		}
		jenv->ReleaseLongArrayElements(objArray, vertexPointers, 0);
		node->setVertices(vertices.data(), arrayLength);
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1setIndicies(JNIEnv *jenv, jclass jcls, jlong nodePointer, jintArray objArray) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}
		if(objArray==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Indices array cannot be null");
		}
		int arrayLength=jenv->GetArrayLength(objArray);
		std::vector<u16>indices;
		jint*values=jenv->GetIntArrayElements(objArray,0);
		for(int i=0;i<arrayLength;i++){
			u16 val=(u16)values[i];
			indices.push_back(val);
		}

		jenv->ReleaseIntArrayElements(objArray, values, 0);
		node->setIndices(indices.data(),arrayLength);
	}

	__declspec(dllexport) jintArray JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1getIndicies(JNIEnv *jenv, jclass jcls, jlong nodePointer) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}

		int count=node->getIndicesCount();
		jintArray intArray=jenv->NewIntArray(count);
		jint*values=jenv->GetIntArrayElements(intArray, NULL);
		u16*indices=node->getIndices();
		for(int i=0;i<count;i++){
			values[i]=indices[i];
		}

		jenv->ReleaseIntArrayElements(intArray, values, NULL);
		return intArray;
	}

	__declspec(dllexport) jlongArray JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1getVertices(JNIEnv *jenv, jclass jcls, jlong nodePointer) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}

		int count=node->getVertexCount();
		jlongArray longArray=jenv->NewLongArray(count);
		jlong*values=jenv->GetLongArrayElements(longArray, NULL);
		S3DVertex*vertices=node->getVertices();
		for(int i=0;i<count;i++){
			values[i]=(jlong)(&vertices[i]);
		}

		jenv->ReleaseLongArrayElements(longArray, values, NULL);
		return longArray;
	}

	__declspec(dllexport) jint JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1getIndicesCount(JNIEnv *jenv, jclass jcls, jlong nodePointer) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}
		node->getAbsolutePosition();
		return (jint)node->getIndicesCount();
	}

	__declspec(dllexport) jint JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1getVerticesCount(JNIEnv *jenv, jclass jcls, jlong nodePointer) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}
		return (jint)node->getVertexCount();
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNI_ICustomizableTriangleMeshNode_1recalculate(JNIEnv *jenv, jclass jcls, jlong nodePointer) {
		ICustomizableTriangleMeshNode*node=(ICustomizableTriangleMeshNode*)nodePointer;
		if(node==NULL){
			SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "Node cannot be null");
		}
		node->recalculate();
	}

	__declspec(dllexport) jlong JNICALL Java_org_swig_jirr_JirrJNI_IGPUProgrammingServices_1addCGShader(JNIEnv *jenv, jclass jcls, jlong gpuServicePointer, jstring programSource, jint vertexTarget, jint pixelTarget, jint baseMaterialType) {
		MyShaderCallBack*mc=new MyShaderCallBack();
		IGPUProgrammingServices*gpu=(IGPUProgrammingServices*)gpuServicePointer;
		E_VERTEX_SHADER_TYPE vertexShaderTarget=(E_VERTEX_SHADER_TYPE)vertexTarget;
		E_PIXEL_SHADER_TYPE pixelShaderTarget=(E_PIXEL_SHADER_TYPE)pixelTarget;
		E_MATERIAL_TYPE emtBaseMaterialType=(E_MATERIAL_TYPE)baseMaterialType;
		char *nativeString = (char *)jenv->GetStringUTFChars(programSource, 0);
		s32 shaderIndex=gpu->addHighLevelShaderMaterial(
			nativeString,
			"vertexMain",
			vertexShaderTarget,
			nativeString,
			"fragmentMain",
			pixelShaderTarget,
			mc,
			emtBaseMaterialType,
			0,
			EGSL_CG);

		jenv->ReleaseStringUTFChars(programSource, nativeString);
		return shaderIndex;
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNICustom_IVideoDriverDrawAaBbSquare(JNIEnv *jenv, jclass jcls, jlong vectorPointer, jlong videoDriverPointer, jfloat length) {
		IVideoDriver*driver=(IVideoDriver*)videoDriverPointer;
		vector3df*vector=(vector3df*)vectorPointer;
		vector3df vector2(vector->X+length,vector->Y,vector->Z);
		driver->draw3DLine(*vector,vector2);
		vector2.X=vector->X;
		vector2.Z=vector->Z+length;
		driver->draw3DLine(*vector,vector2);

		vector3df vector3(vector->X+length,vector->Y,vector->Z+length);
		driver->draw3DLine(vector3,vector2);
		vector2.X=vector->X+length;
		vector2.Z=vector->Z;
		driver->draw3DLine(vector3,vector2);
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNICustom_CMatrixTransformVector(JNIEnv *jenv, jclass jcls, jlong matrixPointer, jlong vectorPointer) {
		if(matrixPointer==0){
			 SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "matrix is null");
		}

		if(vectorPointer==0){
			 SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "vector is null");
		}
		matrix4*matrix=(matrix4*)matrixPointer;
		vector3df*vector=(vector3df*)vectorPointer;
		matrix->transformVect(*vector);
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNICustom_CMatrixTextureTranslate(JNIEnv *jenv, jclass jcls, jlong matrixPointer, jfloat x, jfloat y) {
		if(matrixPointer==0){
			 SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "matrix is null");
		}

		matrix4*matrix=(matrix4*)matrixPointer;
		matrix->setTextureTranslate(x,y);
	}

	__declspec(dllexport) void JNICALL Java_org_swig_jirr_JirrJNICustom_CMatrixTextureScale(JNIEnv *jenv, jclass jcls, jlong matrixPointer, jfloat x, jfloat y) {
		if(matrixPointer==0){
			 SWIG_JavaThrowException_(jenv, SWIG_JavaNullPointerException, "matrix is null");
		}

		matrix4*matrix=(matrix4*)matrixPointer;
		matrix->setTextureScale(x,y);
	}


	__declspec(dllexport) jboolean JNICALL Java_org_swig_jirr_JirrJNI_IVideoDriver_1unloadCGShader(JNIEnv *jenv, jclass jcls, jlong driverPointer, jlong shaderIndex) {
		IVideoDriver*driver=(IVideoDriver*)driverPointer;
		return driver->unloadMaterialRenderer((s32)shaderIndex);
	}
}